package com.cby.springboot.demo.controller;

import com.cby.springboot.demo.bean.Book;
import com.cby.springboot.demo.bean.Result;
import com.cby.springboot.demo.bean.User;
import com.cby.springboot.demo.service.LibraryService;
import com.cby.springboot.demo.service.UserService;
import com.cby.springboot.demo.utils.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.HtmlUtils;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;

@Controller
@RequestMapping("/api")
public class ApiController extends BaseController{

    @Autowired
    UserService userService;

    @CrossOrigin
    @PostMapping(value = "/login")
    @ResponseBody
    public Result login(@RequestBody User user) {
        logI("login");
        if (user != null) {
            logI(user.toString());
        }
        // 对 html 标签进行转义，防止 XSS 攻击
        String username = user.getUserName();
        username = HtmlUtils.htmlEscape(username);
        user.setUserName(username);

//        //从数据库中查询用户信息
//        User loginUser = userService.getByUserName(user);
//
//        if (loginUser == null) {
//            return new Result(2001,"用户不存在");
//        }
//        // 先获取该用户的盐字段
//        String salt = loginUser.getSalt();
//        // 设置 hash 算法迭代次数
//        int times = 2;
//        // 然后在进行hash，得到 hash 后的密码
//        String encodedPassword = new SimpleHash("md5", user.getPassword(), salt, times).toString();
//        // 得到 hash后的密码再进比较是否相等
//        if(encodedPassword.equals(loginUser.getPassword())) {
//            return new Result(2000,"登录成功");
//        }else {
//            return new Result(2002,"账号或者密码错误");
//        }

        Subject subject = SecurityUtils.getSubject();
        //subject.getSession().setTimeout(10000);
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, user.getPassword());
        usernamePasswordToken.setRememberMe(true);
        try {
            subject.login(usernamePasswordToken);
            return new Result(2000, "登录成功");
        } catch (AuthenticationException e) {
            String message = "账号密码错误";
            return new Result(2002, "账号或者密码错误");
        }
    }

    @CrossOrigin
    @PostMapping(value = "/register")
    @ResponseBody
    public Result register(@RequestBody User user) {
        logI("register");
        if(user != null) {
            user.setUserId(UUID.randomUUID().toString());
            logI(user.toString());
        }

        if(user != null && !StringUtils.hasText(user.getEmail())){
            logI("注册失败 - 邮箱不能为空");
            return new Result(1001,"邮箱不能为空");
        }

        if(user != null && !StringUtils.hasText(user.getUserName())){
            logI("注册失败 - 用户名不能为空");
            return new Result(1002,"邮箱不能为空");
        }

        if(user != null && !StringUtils.hasText(user.getPassword())) {
            logI("注册失败 - 密码不能为空");
            return new Result(1003,"密码不能为空");
        }

        //从数据库中查询用户信息
        User loginUser = userService.getByUserName(user.getUserName());
        if(loginUser != null) {
            logI("注册失败 - 用户已经存在");
            return new Result(1004,"用户已经存在");
        }

        // 生成盐,默认长度 16 位
        String salt = new SecureRandomNumberGenerator().nextBytes().toString();
        // 设置 hash 算法迭代次数
        int times = 2;
        // 得到 hash 后的密码
        String encodedPassword = new SimpleHash("md5", user.getPassword(), salt, times).toString();
        //存储用户信息，包括 salt 与 hash 后的密码
        user.setSalt(salt);
        user.setPassword(encodedPassword);
        logI("salt = "+ salt + ", encodedPassword = "+encodedPassword);
        //从数据库中查询用户信息
        int result = userService.insert(user);
        if (result > 0) {
            return new Result(1000,"注册成功");
        } else {
            logI("注册失败");
            return new Result(1005,"注册失败");
        }
    }

    @CrossOrigin
    @GetMapping("/logout")
    @ResponseBody
    public Result logout() {
        logI("do logout");
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        String message = "成功登出";
        return new Result(3000,message);
    }

    /**
     * 即访问每个页面前都向后端发送一个请求，目的是经由拦截器验证服务器端的登录状态，防止上述情况的发生
     * @return
     */
    @CrossOrigin
    @GetMapping(value = "/authentication")
    @ResponseBody
    public String authentication(){
        return "身份认证成功";
    }

    @Autowired
    LibraryService libraryService;

    @CrossOrigin
    @GetMapping(value = "/categories/{cid}/books")
    @ResponseBody
    public List<Book> getBooksById(@PathVariable("cid") int id) {
        logI("getBooksById");
        return libraryService.findAllByCategory(id);
    }

    @CrossOrigin
    @RequestMapping(value = "/search")
    @ResponseBody
    public List<Book> getBooksByTitleOrAuthor(String keyword) {
        logI("getBooksByTitleOrAuthor, keyword = "+keyword);
        return libraryService.findAllByTitleLikeOrAuthorLike(keyword, keyword);
    }

    @CrossOrigin
    @RequestMapping(value = "/books")
    @ResponseBody
    public List<Book> getBooks() {
        List<Book> books = libraryService.list();
        return books;
    }

    @CrossOrigin
    @RequestMapping(value = "/add")
    @ResponseBody
    public int addBook(@RequestBody Book book) {
        logI("book = "+book.toString());
        return libraryService.addBook(book);
    }

    @CrossOrigin
    @PostMapping(value = "/delete")
    @ResponseBody
    public int deleteById(@RequestBody Book book) {
        logI("ID = "+book.getId());
        return libraryService.deleteById(book.getId());
    }

    @CrossOrigin
    @GetMapping(value = "/init")
    @ResponseBody
    public Result init() {
        logI("init");
        return new Result(200);
    }

    @CrossOrigin
    @PostMapping("/covers")
    @ResponseBody
    public String coversUpload(MultipartFile file) throws Exception {
        String folder = "/Users/chenbaoyang/IdeaProjects/SpringBootDemo/img/";
        File imageFolder = new File(folder);
        File f = new File(imageFolder, StringUtils.getRandomString(6) + file.getOriginalFilename()
                .substring(file.getOriginalFilename().length() - 4));
        if (!f.getParentFile().exists())
            f.getParentFile().mkdirs();
        try {
            file.transferTo(f);
            String imgURL = "http://localhost:8081/api/file/" + f.getName();
            return imgURL;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}
